import type {
  ApiAnniversary,
  ApiCycleLog,
  ApiCyclePrediction,
  ApiDiaryEntry,
  ApiDiaryComment,
  ApiRelationship,
  ApiTokenResponse,
  ApiUser,
  ApiAISuggestion,
  ApiChatHistory,
  ApiCycleDayLog,
  ApiDecisionPreset,
  ApiDecisionSpinResult,
} from '../types'
import { request, requestStream } from '../../lib/http'

export type LoginPayload =
  | { email: string; password: string; username?: string }
  | { username: string; password: string; email?: string }

export const AuthAPI = {
  login: (data: LoginPayload) => request<ApiTokenResponse>('/auth/login', { method: 'POST', body: data }),
  register: (data: { email: string; username: string; password: string }) =>
    request<ApiUser>('/auth/register', { method: 'POST', body: data }),
  resendVerification: (data: { email: string }) =>
    request<{ sent: boolean }>('/auth/resend-verification', { method: 'POST', body: data }),
  verifyEmail: (data: { email: string; code: string }) =>
    request<{ verified: boolean }>('/auth/verify-email', { method: 'POST', body: data }),
  forgotPassword: (data: { email: string }) =>
    request<{ ok: boolean }>('/auth/forgot-password', { method: 'POST', body: data }),
  resetPassword: (data: { token: string; new_password: string }) =>
    request<{ ok: boolean }>('/auth/reset-password', { method: 'POST', body: data }),
  getProfile: () => request<ApiUser>('/users/me'),
  updateProfile: (data: { username?: string; nickname?: string | null; partner_profile?: ApiUser['partner_profile'] }) =>
    request<ApiUser>('/users/me', { method: 'PUT', body: data }),
  updatePreferences: (prefs: Record<string, unknown>) =>
    request<ApiUser>('/users/me/preferences', { method: 'PUT', body: { prefs } }),
  logout: (refreshToken: string | null) =>
    refreshToken
      ? request<void>('/auth/logout', { method: 'POST', body: { refresh_token: refreshToken } }).catch(() => undefined)
      : Promise.resolve(),
}

export const RelationshipAPI = {
  listMine: () => request<ApiRelationship[]>('/relationships/me'),
  invite: () => request<ApiRelationship>('/relationships/invite', { method: 'POST', body: {} }),
  join: (inviteCode: string) => request<ApiRelationship>('/relationships/join', { method: 'POST', body: { invite_code: inviteCode } }),
  leave: (relationshipId: number) =>
    request<void>(`/relationships/${relationshipId}/leave`, { method: 'POST', body: {} }),
}

type PaginatedResponse<T> = { items: T[]; next_offset: number | null }

export const DiaryAPI = {
  list: (params?: { limit?: number; offset?: number }) => {
    const search = new URLSearchParams()
    if (params?.limit && params.limit > 0) {
      search.set('limit', String(params.limit))
    }
    if (params?.offset && params.offset > 0) {
      search.set('offset', String(params.offset))
    }
    const qs = search.toString()
    return request<PaginatedResponse<ApiDiaryEntry>>(`/diary${qs ? `?${qs}` : ''}`)
  },
  getOne: (entryId: number, params?: { comment_limit?: number; comment_offset?: number }) => {
    const search = new URLSearchParams()
    if (params?.comment_limit && params.comment_limit > 0) {
      search.set('comment_limit', String(params.comment_limit))
    }
    if (params?.comment_offset && params.comment_offset > 0) {
      search.set('comment_offset', String(params.comment_offset))
    }
    const qs = search.toString()
    return request<
      ApiDiaryEntry & { comments: ApiDiaryComment[]; comments_meta?: { next_offset: number | null; total: number | null } }
    >(`/diary/${entryId}${qs ? `?${qs}` : ''}`)
  },
  listComments: (entryId: number, params?: { limit?: number; offset?: number }) => {
    const search = new URLSearchParams()
    if (params?.limit && params.limit > 0) {
      search.set('limit', String(params.limit))
    }
    if (params?.offset && params.offset > 0) {
      search.set('offset', String(params.offset))
    }
    const qs = search.toString()
    return request<PaginatedResponse<ApiDiaryComment>>(`/diary/${entryId}/comments${qs ? `?${qs}` : ''}`)
  },
  addComment: (entryId: number, data: { content: string; mood?: string | null }) =>
    request<ApiDiaryComment>(`/diary/${entryId}/comments`, { method: 'POST', body: data }),
  deleteComment: (entryId: number, commentId: number) =>
    request<void>(`/diary/${entryId}/comments/${commentId}`, { method: 'DELETE' }),
  create: (data: {
    title?: string
    content_md: string
    mood?: string | null
    tags?: string[]
    visibility?: string
    notify_partner?: boolean
    allow_ai_summary?: boolean
  }) => request<ApiDiaryEntry>('/diary', { method: 'POST', body: data }),
  update: (entryId: number, data: Partial<{ title: string; content_md: string; mood?: string | null; tags?: string[]; visibility?: string }>) =>
    request<ApiDiaryEntry>(`/diary/${entryId}`, { method: 'PUT', body: data }),
  remove: (entryId: number) => request<void>(`/diary/${entryId}`, { method: 'DELETE' }),
}

export const AnniversaryAPI = {
  list: (params?: { limit?: number; offset?: number }) => {
    const search = new URLSearchParams()
    if (params?.limit && params.limit > 0) search.set('limit', String(params.limit))
    if (params?.offset && params.offset > 0) search.set('offset', String(params.offset))
    const qs = search.toString()
    return request<PaginatedResponse<ApiAnniversary>>(`/anniversaries${qs ? `?${qs}` : ''}`)
  },
  create: (data: { name: string; recurrence: string; reminder_offset_days: number; is_lunar?: boolean; lunar_date_str?: string | null; countdown_mode?: 'down'|'up'|'both'; date?: string }) =>
    request<ApiAnniversary>('/anniversaries', { method: 'POST', body: data }),
  update: (id: number, data: Partial<{ name: string; date: string; recurrence: string; reminder_offset_days: number; is_lunar?: boolean; lunar_date_str?: string | null; countdown_mode?: 'down'|'up'|'both' }>) =>
    request<ApiAnniversary>(`/anniversaries/${id}`, { method: 'PUT', body: data }),
  remove: (id: number) => request<void>(`/anniversaries/${id}`, { method: 'DELETE' }),
}

export const CycleAPI = {
  listLogs: () => request<ApiCycleLog[]>('/cycle/logs'),
  listPredictions: () => request<ApiCyclePrediction[]>('/cycle/predictions'),
  createLog: (data: { start_date: string; end_date?: string | null; symptoms?: Record<string, unknown>; notes?: string | null }) =>
    request<ApiCycleLog>('/cycle/logs', { method: 'POST', body: data }),
  updateLog: (
    logId: number,
    data: Partial<{ start_date: string; end_date?: string | null; symptoms?: Record<string, unknown>; notes?: string | null }>,
  ) => request<ApiCycleLog>(`/cycle/logs/${logId}`, { method: 'PUT', body: data }),
  removeLog: (logId: number) => request<void>(`/cycle/logs/${logId}`, { method: 'DELETE' }),
  listDayLogs: (params: { month: number; year: number }) =>
    request<ApiCycleDayLog[]>(`/cycle/day-logs?month=${params.month}&year=${params.year}`),
  upsertDayLog: (data: { date: string; flow_level: string; symptoms?: Record<string, unknown> | null; mood?: string | null; temperature?: number | null }) =>
    request<{ ok: boolean }>(`/cycle/day-logs`, { method: 'POST', body: data }),
  deleteDayLog: (date: string) =>
    request<{ ok: boolean }>(`/cycle/day-logs?date=${encodeURIComponent(date)}`, { method: 'DELETE' }),
}

export const AIAPI = {
  suggest: (body: { entry_context: string; mood?: string | null; tags: string[]; provider?: string | null }) =>
    request<ApiAISuggestion>('/ai/suggest', { method: 'POST', body }),
  fetchHistory: (params: { thread_id?: string | null; offset?: number; limit?: number }) => {
    const search = new URLSearchParams()
    if (params.thread_id) search.set('thread_id', params.thread_id)
    if (typeof params.offset === 'number') search.set('offset', String(params.offset))
    if (typeof params.limit === 'number') search.set('limit', String(params.limit))
    const query = search.toString()
    return request<ApiChatHistory>(`/ai/chat/history${query ? `?${query}` : ''}`)
  },
  streamChat: (
    body: { thread_id?: string | null; message: string; provider?: string | null },
    options?: { signal?: AbortSignal },
  ) => requestStream('/ai/chat/stream', { method: 'POST', body, signal: options?.signal }),
  getMemoryProposals: () => request<{ proposals: Record<string, Record<string, number>> | null }>(`/ai/memory/proposals`),
  commitMemoryProposals: (data: { likes?: string[]; dislikes?: string[]; topics?: string[]; reminders?: string[]; agreements?: string[]; boundaries?: string[] }) =>
    request<{ ok: boolean }>(`/ai/memory/proposals/commit`, { method: 'POST', body: data }),
  clearMemoryProposals: () => request<{ ok: boolean }>(`/ai/memory/proposals/clear`, { method: 'POST', body: {} }),
}

export const DecisionAPI = {
  list: (params?: { limit?: number; offset?: number }) => {
    const search = new URLSearchParams()
    if (params?.limit && params.limit > 0) search.set('limit', String(params.limit))
    if (params?.offset && params.offset > 0) search.set('offset', String(params.offset))
    const qs = search.toString()
    return request<{ items: ApiDecisionPreset[]; offset: number; limit: number }>(
      `/decision-presets${qs ? `?${qs}` : ''}`,
    )
  },
  create: (payload: { title: string; options: string[]; style?: string; is_shared?: boolean; color_seed?: string | null }) =>
    request<ApiDecisionPreset>('/decision-presets', { method: 'POST', body: payload }),
  update: (
    id: number,
    payload: Partial<{ title: string; options: string[]; style: string; is_shared: boolean; color_seed?: string | null }>,
  ) => request<ApiDecisionPreset>(`/decision-presets/${id}`, { method: 'PUT', body: payload }),
  remove: (id: number) => request<void>(`/decision-presets/${id}`, { method: 'DELETE' }),
  quickSpin: (payload: { title?: string; options: string[]; style?: string }) =>
    request<ApiDecisionSpinResult>('/decision-presets/quick-spin', { method: 'POST', body: payload }),
  spinSaved: (id: number) =>
    request<ApiDecisionSpinResult>(`/decision-presets/${id}/spin`, { method: 'POST', body: {} }),
}
